import * as maxrect from "../maxrects_packer/src/index.js"
import { Color32 } from "./color.js";
import { RectRange } from "./rect.js";
export class TTImgData {
    data: Uint8Array;
    width: number;
    height: number;
    borderX1: number = 0;
    borderY1: number = 0;
    borderX2: number = 0;
    borderY2: number = 0;
}
//Target2D是对ImageBitmap的封装，由于他的设计有点2b，所以封装一下
export class Target2D {
    protected _canvas: OffscreenCanvas = new OffscreenCanvas(256, 256);
    protected _r2d: OffscreenCanvasRenderingContext2D;
    protected bitmap: ImageBitmap;

    constructor(width: number, height: number) {
        this._canvas = new OffscreenCanvas(width, height);
        this._r2d = this._canvas.getContext("2d", { willReadFrequently: true });
        this._canvas.transferToImageBitmap();
        this._r2d.imageSmoothingEnabled = false;
    }
    getWidth(): number {
        return this._canvas.width;
    }
    getHeight(): number {
        return this._canvas.height;
    }
    setWidth(width: number): void {
        this._canvas.width = width;
    }
    setHeight(height: number): void {
        this._canvas.height = height;
    }
    getContext(): OffscreenCanvasRenderingContext2D {
        return this._r2d;
    }
    getCanvas(): OffscreenCanvas {
        return this._canvas;
    }
    getBitmap(): ImageBitmap {
        return this.bitmap;
    }


    //每次UpdateBitmap之后，应该要引发重绘
    updateBitmap() {
        // if (renderFunc != null)
        //     renderFunc();

        if (this.bitmap = null)
            this.bitmap.close();//先灭掉上一个bitmap

        this.bitmap = this._canvas.transferToImageBitmap();


    }
}
//一个绘图区域
export class DrawArea extends Target2D {

  
    Resize_Scale(neww: number, newh: number, linear: boolean) {
        if (neww == this.getWidth() && newh == this.getHeight()) {
            return;
        }

        //方案1，硬算像素
        let sw = this.getWidth();
        let sh = this.getHeight();
        // let olddata = this.getContext().getImageData(0, 0, sw, sh);
        // this.setWidth(neww);
        // this.setHeight(newh);
        // let newdata = new ImageData(neww, newh);
        // let xs = sw / neww;
        // let ys = sh / newh;
        // for (var j = 0; j < newh; j++) {
        //     for (var i = 0; i < neww; i++) {
        //         let srcx = (i * xs) | 0;
        //         let srcy = (j * ys) | 0;
        //         let srci = (srcy * sw + srcx) * 4;
        //         let newi = (j * neww + i) * 4;
        //         newdata.data[newi + 0] = olddata.data[srci + 0];
        //         newdata.data[newi + 1] = olddata.data[srci + 1];
        //         newdata.data[newi + 2] = olddata.data[srci + 2];
        //         newdata.data[newi + 3] = olddata.data[srci + 3];
        //     }
        // }
        // this.getContext().putImageData(newdata, 0, 0);

        //方案2，画一遍不就完了
        this.setWidth(neww);
        this.setHeight(newh);
        this._r2d.imageSmoothingEnabled = linear;
        this._r2d.drawImage(this.bitmap, 0, 0, sw, sh, 0, 0, neww, newh);

        this._r2d.imageSmoothingEnabled = false;
        this.updateBitmap();
    }

    Resize_Cut(neww: number, newh: number, dirx: number, diry: number): void {
        if (neww == this.getWidth() && newh == this.getHeight()) {
            return;
        }


        let sw = this.getWidth();
        let sh = this.getHeight();
        this.setWidth(neww);
        this.setHeight(newh);

        let x = 0;
        let y = 0;
        if (dirx == -1) {
            x = 0;
        }
        else if (dirx == 0) {
            x = ((neww - sw) / 2) | 0
        }
        else if (dirx == 1) {
            x = (neww - sw)
        }

        if (diry == -1) {
            y = 0;
        }
        else if (diry == 0) {
            y = ((newh - sh) / 2) | 0
        }
        else if (diry == 1) {
            y = (newh - sh)
        }
        this._r2d.drawImage(this.bitmap, x, y);
        this.updateBitmap();
    }
    DrawArea_Init(img: HTMLImageElement | ImageBitmap): void {
        this.setWidth(img.width);
        this.setHeight(img.height);
        this._r2d.drawImage(img, 0, 0);
        this.updateBitmap();
    }
    updateBitmap(): void {

        super.updateBitmap();

        this._r2d.drawImage(this.bitmap, 0, 0);
    }
    UpdateSubArea(imgdata: ImageData, x: number, y: number): void {
        if (this.bitmap != null) {
            this._r2d.drawImage(this.bitmap, 0, 0);
        }
        this._r2d.putImageData(imgdata, x, y);
        this.updateBitmap();
    }
    ClearColor(color: Color32): void {
        //this._r2d.beginPath();
        this._r2d.fillStyle = color.toString();

        this._r2d.fillRect(0, 0, this.getWidth(), this.getHeight());
        //this._r2d.closePath();
    }
    ClearRect(x: number, y: number, w: number, h: number): void {
        this._r2d.clearRect(x, y, w, h);
    }
    DrawRect(x: number, y: number, w: number, h: number, color: Color32): void {
        // if (color.A < 16) {
        //     this._r2d.globalAlpha = 1.0;

        //     this._r2d.save();


        //     this._r2d.beginPath();
        //     this._r2d.fillStyle = color.toString();
        //     this._r2d.lineWidth = 1;
        //     this._r2d.rect(x, y, 5, 5);
        //     this._r2d.closePath();

        //     this._r2d.clip();
        //     this._r2d.clearRect(x, y, 5, 5);
        //     this._r2d.restore();
        //     return;
        // }

        //this._r2d.beginPath();
        this._r2d.fillStyle = color.toString();
        this._r2d.lineWidth = 1;
        this._r2d.fillRect(x, y, w, h);
        //this._r2d.closePath();
    }
}
export class ImgTool {
    static _backrender: Target2D = new Target2D(256, 256);

    static Bin2Url(bin: Uint8Array): string {
        let blob = new Blob([bin]);
        return URL.createObjectURL(blob);
    }
    static Url2ImgAsync(url: string): Promise<HTMLImageElement> {
        return new Promise<HTMLImageElement>((resolve, reject) => {
            let img = document.createElement("img");
            img.src = url;
            img.onload = () => {
                resolve(img);
            }
            img.onerror = () => {
                reject("img load fail.");
            }
        });

    }
    static async Bin2ImgAsync(bin: Uint8Array): Promise<HTMLImageElement> {
        let img = await this.Url2ImgAsync(this.Bin2Url(bin));
        return img;
    }
    static CreateImgData(width: number, height: number): ImageData {

        return this._backrender.getContext().createImageData(width, height);

    }
    static async Bin2ImgDataAsync(bin: Uint8Array): Promise<ImageData> {

        let img = await this.Bin2ImgAsync(bin);
        return this.Img2Data(img);
    }
    static Img2Data(img: HTMLImageElement): ImageData {

        this._backrender.setWidth(img.width);
        this._backrender.setHeight(img.height);
        this._backrender.getContext().drawImage(img, 0, 0);


        let imgdata = this._backrender.getContext().getImageData(0, 0, this._backrender.getWidth(), this._backrender.getHeight());
        return imgdata;
    }
    private static async Canvas2PngFileDataAsync(): Promise<Uint8Array> {
        let b = await this._backrender.getCanvas().convertToBlob({ "type": "image/png" });
        let ab = await b.arrayBuffer();
        return new Uint8Array(ab);
    }
    static async ImgData2BlobAsync(data: ImageData): Promise<Blob> {
        this._backrender.setWidth(data.width);
        this._backrender.setHeight(data.height);
        this._backrender.getContext().putImageData(data, 0, 0);
        let b = await this._backrender.getCanvas().convertToBlob({ "type": "image/png" });
        return b;
      
    }
    static async ImgData2PngFileDataAsync(data: ImageData): Promise<Uint8Array> {
        this._backrender.setWidth(data.width);
        this._backrender.setHeight(data.height);
        this._backrender.getContext().putImageData(data, 0, 0);

        return await this.Canvas2PngFileDataAsync();
    }
    static async PutToImgData(target: ImageData, src: ImageData | TTImgData, x: number, y: number) {
        for (var j = 0; j < src.height; j++) {
            for (var i = 0; i < src.width; i++) {
                var dx = i + x;
                var dy = j + y;
                if (dx < 0 || dx >= target.width) continue;
                if (dy < 0 || dy >= target.height) continue;
                var srci = (j * src.width + i) * 4;
                var desti = (dy * target.width + dx) * 4;

                target.data[desti + 0] = src.data[srci + 0];
                target.data[desti + 1] = src.data[srci + 1];
                target.data[desti + 2] = src.data[srci + 2];
                target.data[desti + 3] = src.data[srci + 3];
            }
        }
    }
    static ImgFill(src: ImageData | TTImgData): TTImgData {
        let img = new TTImgData()
        {
            img.width = src.width;
            img.height = src.height;
            img.data = new Uint8Array(src.width * src.height * 4);
            for (var i = 0; i < img.data.length; i++) {
                img.data[i] = src.data[i];
            }
        }
        return img;
    }
    static ImgCut(src: ImageData | TTImgData): TTImgData {
        let x1 = src.width;
        let x2 = 0;
        let y1 = src.width;
        let y2 = 0;
        for (var y = 0; y < src.height; y++) {
            for (var x = 0; x < src.width; x++) {
                let a = src.data[(y * src.width + x) * 4 + 3];
                if (a > 0) {
                    if (x < x1)
                        x1 = x;
                    if (y < y1)
                        y1 = y;
                    if (x > x2)
                        x2 = x;
                    if (y > y2)
                        y2 = y;
                }
            }
        }

        let img = new TTImgData();
        img.borderX1 = x1;
        img.borderY1 = y1;
        img.borderX2 = src.width - 1 - x2
        img.borderY2 = src.height - 1 - y2;
        let width = img.width = x2 - x1 + 1;
        let height = img.height = y2 - y1 + 1;
        img.data = new Uint8Array(width * height * 4);
        for (var sy = 0; sy < height; sy++) {
            for (var sx = 0; sx < width; sx++) {
                let srcseek = ((sy + y1) * src.width + (sx + x1)) * 4;
                let destseek = (sy * width + sx) * 4;
                img.data[destseek + 0] = src.data[srcseek + 0];
                img.data[destseek + 1] = src.data[srcseek + 1];
                img.data[destseek + 2] = src.data[srcseek + 2];
                img.data[destseek + 3] = src.data[srcseek + 3];
            }
        }
        return img;
    }
    static Pack(width: number, height: number, border: number, rects: MyRect[]): Bin[] {
        let mr = new maxrect.MaxRectsPacker<MyRect>(width, height, border);
        mr.addArray(rects);
        let bins: Bin[] = [];
        for (var i = 0; i < mr.bins.length; i++) {
            let bin = new Bin();
            for (var j = 0; j < mr.bins[i].rects.length; j++) {
                bin.rects.push(mr.bins[i].rects[j]);
            }
            bins.push(bin);
        }
        return bins;
    }
}
export class Bin {
    rects: MyRect[] = []
}
export class MyRect implements maxrect.IRectangle {
    name: string;
    get width(): number {
        return this.imgdata.width;
    }
    get height(): number {
        return this.imgdata.height;
    }
    x: number
    y: number
    imgdata: TTImgData;
    constructor(name: string, imgdata: TTImgData) {
        this.name = name;
        this.imgdata = imgdata;
        this.x = 0;
        this.y = 0;
    }
}